package org.shean.app.rssreader;

import java.util.ArrayList;
import java.util.List;

import org.shean.app.rssreader.provider.SzRSSReader;
import org.shean.app.rssreader.utils.ChannelSource;
import org.shean.app.rssreader.utils.DownloadManager;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.MergeCursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AlphabetIndexer;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.ViewFlipper;

public class ChannelListActivity extends ListActivity implements
		View.OnCreateContextMenuListener {

	private static final int ALL_CHANNEL = -1;

	private ChannelListAdapter mAdapter;
	private Cursor mChannelCursor;
	private boolean mAdapterSent = false;
	
	private DownloadManager mDownloadManager;
	private Handler mRefreshHandler;
	
	public List<String> mRefreshList = new ArrayList<String>();

	public static final int SELECT_ID = Menu.FIRST;
	public static final int INSERT_ID = Menu.FIRST + 1;
	public static final int REFRESH_ALL_ID = Menu.FIRST + 2;
	public static final int DELETE_ALL_ID = Menu.FIRST + 3;
	public static final int SETTING_ID = Menu.FIRST + 4;

	public static final int REFRESH_ID = Menu.FIRST + 5;
	public static final int MARK_READ_ID = Menu.FIRST + 6;
	public static final int RENAME_ID = Menu.FIRST + 7;
	public static final int DELETE_ID = Menu.FIRST + 8;
	public static final int DETAIL_ID = Menu.FIRST + 9;
	
	private static final int RENAME_TITLE = 1;

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.channel_picker_activity);
		ListView lv = getListView();
		lv.setFastScrollEnabled(true);
		lv.setOnCreateContextMenuListener(this);
		lv.setTextFilterEnabled(true);

		mAdapter = (ChannelListAdapter) getLastNonConfigurationInstance();
		if (mAdapter == null) {
			// Log.i("@@@", "starting query");
			mAdapter = new ChannelListAdapter(getApplication(), this,
					R.layout.channel_list_item, mChannelCursor,
					new String[] {}, new int[] {});
			setListAdapter(mAdapter);
			setTitle(R.string.app_name);
			getChannelCursor(mAdapter.getQueryHandler(), null);
		} else {
			mAdapter.setActivity(this);
			setListAdapter(mAdapter);
			mChannelCursor = mAdapter.getCursor();
			if (mChannelCursor != null) {
				init(mChannelCursor);
			} else {
				getChannelCursor(mAdapter.getQueryHandler(), null);
			}
		}
	}

	@Override
	public void onResume() {
		super.onResume();
		if (mChannelCursor != null) {
			mChannelCursor.requery();
		}
		getListView().invalidateViews();
	}

	@Override
	public void onPause() {
		mReScanHandler.removeCallbacksAndMessages(null);
		super.onPause();
	}

	@Override
	public void onDestroy() {
		if (!mAdapterSent) {
			Cursor c = mAdapter.getCursor();
			if (c != null) {
				c.close();
			}
		}
		super.onDestroy();
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		Uri uri = ContentUris.withAppendedId(
				SzRSSReader.Posts.CONTENT_URI_LIST, id);
		startActivity(new Intent(Intent.ACTION_VIEW, uri));
	}

	@Override
	public Object onRetainNonConfigurationInstance() {
		mAdapterSent = true;
		return mAdapter;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		//menu.add(0, SELECT_ID, 0, "Select Channel");
		menu.add(0, INSERT_ID, 1, "Add Channel");
		menu.add(0, REFRESH_ALL_ID, 2, "Refresh All");
		menu.add(0, DELETE_ALL_ID, 3, "Delete All");
		menu.add(0, SETTING_ID, 4, "Setting");
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		super.onPrepareOptionsMenu(menu);
		if (mChannelCursor != null && mChannelCursor.getCount() > 1) {
			menu.getItem(2).setVisible(true);
			menu.getItem(3).setVisible(true);
		} else {
			menu.getItem(2).setVisible(false);
			menu.getItem(3).setVisible(false);
		}

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case INSERT_ID:
			startActivity(new Intent(Intent.ACTION_INSERT,
					SzRSSReader.Channels.CONTENT_URI));
			return true;
		case DELETE_ALL_ID:
			showDialog(DELETE_ALL_ID);
			return true;
		case REFRESH_ALL_ID:
			refreshAllChannels();
			return true;
		case SETTING_ID:
			Intent intent2 = new Intent();
			intent2.setClass(this, SettingActivity.class);
			startActivity(intent2);
			return true;
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo info) {
		menu.setHeaderTitle("Channel Menu");
		// menu.setHeaderIcon(R.drawable.feedicon);
		menu.add(1, REFRESH_ID, 0, "Refresh");
		menu.add(1, MARK_READ_ID, 1, "Mark all readed");
		long id = ((AdapterView.AdapterContextMenuInfo) info).id;
		if (id != ALL_CHANNEL) {
			menu.add(1, RENAME_ID, 2, "Rename");
			menu.add(1, DELETE_ID, 3, "Delete");
			menu.add(1, DETAIL_ID, 4, "Detail");
		}
	}

	private long mCurrentSelectedID = -1;

	@Override
	public boolean onContextItemSelected(MenuItem item) {

		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item
				.getMenuInfo();
		switch (item.getItemId()) {
		case DELETE_ID:
			mCurrentSelectedID = menuInfo.id;
			showDialog(DELETE_ID);
			return true;
		case REFRESH_ID:
			if(menuInfo.id == ALL_CHANNEL)
				refreshAllChannels();
			else
				refreshChannel();
			return true;
		case MARK_READ_ID:
			Uri uri = SzRSSReader.Posts.CONTENT_URI;
			if(menuInfo.id != ALL_CHANNEL)
			{
				uri = ContentUris.withAppendedId(
						SzRSSReader.Posts.CONTENT_URI_LIST, menuInfo.id);
			}
			ContentValues values = new ContentValues();
			values.put(SzRSSReader.Posts.IS_READ, 1);
			getContentResolver().update(uri, values,
					null, null);
			
			getListView().invalidateViews();
			return true;
		case RENAME_ID:
			mCurrentSelectedID = menuInfo.id;
			Intent intent = new Intent();
			intent.setClass(this, RenameChannelAcvtivity.class);
			intent.putExtra("rename", mCurrentSelectedID);
			this.startActivityForResult(intent, RENAME_TITLE);
			return true;
		}
		return super.onContextItemSelected(item);
	}
	
	@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case RENAME_TITLE:
                if (resultCode == RESULT_OK) {
                	if (mChannelCursor != null) {
            			mChannelCursor.requery();
            		}
            		getListView().invalidateViews();
                }
                break;
        }
    }

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DELETE_ID:
			return new AlertDialog.Builder(this).setIcon(
					R.drawable.alert_dialog_icon).setTitle(
					"Delete").setMessage(
					"Are you sure to delete the channel?").setPositiveButton(
					"OK",
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog,
								int whichButton) {

							if (mCurrentSelectedID > -1)
								deleteChannel(mCurrentSelectedID);
							mCurrentSelectedID = -1;
						}
					}).setNegativeButton("Cancel",
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog,
								int whichButton) {
							mCurrentSelectedID = -1;
						}
					}).create();
		case DELETE_ALL_ID:
			return new AlertDialog.Builder(this).setIcon(R.drawable.alert_dialog_icon).setTitle(
					"Delete").setMessage(
					"Are you sure to delete all channels?").setPositiveButton(
					"OK", new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog,
								int whichButton) {

							//delete All Posts
							getContentResolver().delete(SzRSSReader.Posts.CONTENT_URI, null, null);

							//delete All Channels
							getContentResolver().delete(SzRSSReader.Channels.CONTENT_URI, null, null);
							
							mChannelCursor.requery();
							
						}
					}).setNegativeButton("Cancel",
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog,
								int whichButton) {

						}
					}).create();
		}
		return null;
	}
	
    private final void refreshAllChannels()
    {
    	if (mChannelCursor == null || mChannelCursor.getCount() < 2)
    		return;
    	
    	mChannelCursor.moveToFirst();
    	do 
    	{
    		refreshChannel();
    	} while (mChannelCursor.moveToNext() == true);
    }

	private final void deleteChannel(long channelId) {
		/* Delete related posts. */
		getContentResolver().delete(SzRSSReader.Posts.CONTENT_URI,
				"channel_id=?", new String[] { String.valueOf(channelId) });

		getContentResolver().delete(SzRSSReader.Channels.CONTENT_URI, "_id=?",
				new String[] { String.valueOf(channelId) });
	}

	public void init(Cursor c) {
		mAdapter.changeCursor(c); // also sets mArtistCursor

		if (mChannelCursor == null) {
			closeContextMenu();
			mReScanHandler.sendEmptyMessageDelayed(0, 1000);
			return;
		}
	}

	private Handler mReScanHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			getChannelCursor(mAdapter.getQueryHandler(), null);
		}
	};

	private String[] mCols = new String[] { SzRSSReader.Channels._ID,
			SzRSSReader.Channels.TITLE, SzRSSReader.Channels.URL };

	private Cursor getChannelCursor(AsyncQueryHandler async, String filter) {

		Cursor ret = null;

		if (async != null) {
			async.startQuery(0, null, SzRSSReader.Channels.CONTENT_URI, mCols,
					null, null, null);
		} else {
			ret = managedQuery(SzRSSReader.Channels.CONTENT_URI, mCols, null,
					null, null);
		}

		return mergedCursor(ret);
	}
	
	private final void refreshChannel()
    {
    	/* We don't initialize these unless the user requests a refresh.
    	 * The common case is that the background service will be responsible
    	 * for this task, so the behaviour in this activity will rarely be
    	 * invoked.
    	 */
    	if (mDownloadManager == null)
    	{
    		mRefreshHandler = new Handler();
    		mDownloadManager = new DownloadManager(mRefreshHandler);
    	}

    	long channelId =
    		mChannelCursor.getInt(mChannelCursor.getColumnIndex(SzRSSReader.Channels._ID));
    	
    	if(channelId == ALL_CHANNEL)return;

//    	/* Don't refresh the same channel more than once. */
    	if(mRefreshList.contains(Long.toString(channelId)))
    		return;

    	String rssurl = mChannelCursor.getString(mChannelCursor.getColumnIndex(SzRSSReader.Channels.URL));

		Runnable refresh = new RefreshRunnable(mRefreshHandler, this ,channelId, rssurl);

		mDownloadManager.schedule(refresh);
    }
	
	private class RefreshRunnable implements Runnable
    {
    	private Handler mHandler;
    	private ChannelListActivity mActivity;
    	private long mChannelID;
    	private String mRSSURL;

    	public RefreshRunnable(Handler handler, ChannelListActivity activity, long channelId, String rssurl)
    	{
    		mHandler = handler;
    		mActivity = activity;
    		mChannelID = channelId;
    		mRSSURL = rssurl;
    	}

    	public void run()
    	{
			Log.e("RSSChannelList", "Here we go: " + mRSSURL + "...");

			mHandler.post(new Runnable() {
				public void run()
				{
					mRefreshList.add(Long.toString(mChannelID));
					mActivity.getListView().invalidateViews();
				}
			});

			try
			{
				new ChannelSource(ChannelListActivity.this).syncDB(mChannelID, mRSSURL);
			}
			catch (Exception e)
			{
				/* TODO: Handle me somehow... */
				Log.d("RSSChannelList", Log.getStackTraceString(e));
			}

	    	mHandler.post(new Runnable() {
	    		public void run()
	    		{
	    			mRefreshList.remove(Long.toString(mChannelID));
					mActivity.getListView().invalidateViews();
	    		}
	    	});
    	}
    }


	private Cursor mergedCursor(Cursor c) {
		ArrayList<ArrayList> autochannellists = new ArrayList<ArrayList>();

		ArrayList<Object> all_channel = new ArrayList<Object>(3);
		all_channel.add(ALL_CHANNEL);
		all_channel.add("All Channels");
		all_channel.add("abc");
		autochannellists.add(all_channel);

		ArrayListCursor autoplaylistscursor = new ArrayListCursor(mCols,
				autochannellists);

		if (c == null) {
			return autoplaylistscursor;
		}
		if (c instanceof MergeCursor) {
			// this shouldn't happen, but fail gracefully
			Log.d("ChannelListActivity", "Already wrapped");
			return c;
		}

		Cursor cc = new MergeCursor(new Cursor[] { autoplaylistscursor, c });
		return cc;
	}

	static class ChannelListAdapter extends SimpleCursorAdapter {

		private AsyncQueryHandler mQueryHandler;
		private ChannelListActivity mActivity;
		private final BitmapDrawable mDefaultIcon;
		// private final Resources mResources;

		private int mTitleIdx;
		// private AlphabetIndexer mIndexer;

		private boolean mConstraintIsValid = false;
		private String mConstraint = null;

		class ViewHolder {
			TextView line1;
			TextView line2;
			TextView number;
			// ImageView play_indicator;
			ImageView icon;
			// ProgressBar download_progress;
			ViewFlipper flipper;
		}

		class QueryHandler extends AsyncQueryHandler {
			QueryHandler(ContentResolver res) {
				super(res);
			}

			@Override
			protected void onQueryComplete(int token, Object cookie,
					Cursor cursor) {
				// Log.i("@@@", "query complete");
				cursor = mActivity.mergedCursor(cursor);
				mActivity.init(cursor);
			}
		}

		public ChannelListAdapter(Context context,
				ChannelListActivity currentactivity, int layout, Cursor c,
				String[] from, int[] to) {
			super(context, layout, c, from, to);
			mActivity = currentactivity;
			mQueryHandler = new QueryHandler(context.getContentResolver());

			Resources r = context.getResources();

			Bitmap b = BitmapFactory.decodeResource(r, R.drawable.rss_channel);
			mDefaultIcon = new BitmapDrawable(b);
			// no filter or dither, it's a lot faster and we can't tell the
			// difference
			mDefaultIcon.setFilterBitmap(false);
			mDefaultIcon.setDither(false);
			getColumnIndices(c);
			// mResources = context.getResources();
		}

		@Override
		public View newView(Context context, Cursor cursor, ViewGroup parent) {
			View v = super.newView(context, cursor, parent);
			ViewHolder vh = new ViewHolder();
			vh.line1 = (TextView) v.findViewById(R.id.line1);
			vh.line2 = (TextView) v.findViewById(R.id.line2);
			vh.number = (TextView) v.findViewById(R.id.number);
			// vh.play_indicator = (ImageView)
			// v.findViewById(R.id.play_indicator);
			vh.icon = (ImageView) v.findViewById(R.id.icon);
			vh.flipper = (ViewFlipper) v.findViewById(R.id.flipper);
			// vh.icon.setBackgroundDrawable(mDefaultIcon);
			vh.icon.setPadding(0, 0, 1, 0);
			
			vh.flipper.setInAnimation(AnimationUtils.loadAnimation(mActivity,
                    R.anim.push_left_in));
			vh.flipper.setOutAnimation(AnimationUtils.loadAnimation(mActivity,
                    R.anim.push_left_out));
			// vh.download_progress = (ProgressBar)
			// v.findViewById(R.id.download_progress);
			v.setTag(vh);
			return v;
		}

		@Override
		public void bindView(View view, Context context, Cursor cursor) {

			ViewHolder vh = (ViewHolder) view.getTag();

			String name = cursor.getString(mTitleIdx);
			vh.line1.setText(name + " ...");
			vh.line2.setText(name);
			ImageView iv = vh.icon;
			iv.setImageDrawable(mDefaultIcon);

			long channelId = cursor.getLong(cursor
					.getColumnIndex(SzRSSReader.Channels._ID));

			Uri uri = ContentUris.withAppendedId(
					SzRSSReader.Posts.CONTENT_URI_LIST, channelId);

			if (channelId == ALL_CHANNEL)
				uri = SzRSSReader.Posts.CONTENT_URI;

			Cursor unread = context.getContentResolver().query(uri,
					new String[] { SzRSSReader.Posts._ID }, "isRead=0", null,
					null);

			int unreadCount = unread.getCount();
			unread.close();

			vh.number.setText("" + unreadCount);
			
			if (mActivity.mRefreshList.contains(Long.toString(channelId)) && channelId != ALL_CHANNEL)
			{
				vh.line2.setVisibility(View.GONE);
				vh.flipper.setVisibility(View.VISIBLE);
				vh.flipper.startFlipping();
				Log.d("ChannelList","!!!!!!!!!!!!!!!!!!!!! channelId:" + channelId);
			}
			else
			{
				vh.line2.setVisibility(View.VISIBLE);
				vh.flipper.setVisibility(View.GONE);
				
				if(vh.flipper.isFlipping())
				{
					vh.flipper.stopFlipping();
					vh.flipper.setDisplayedChild(0);
				}
			}
		}

		@Override
		public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
			String s = constraint.toString();
			if (mConstraintIsValid
					&& ((s == null && mConstraint == null) || (s != null && s
							.equals(mConstraint)))) {
				return getCursor();
			}
			Cursor c = mActivity.getChannelCursor(null, s);
			mConstraint = s;
			mConstraintIsValid = true;
			return c;
		}

		/*
		 * public int getPositionForSection(int section) { return
		 * mIndexer.getPositionForSection(section); }
		 * 
		 * public int getSectionForPosition(int position) { return 0; }
		 * 
		 * public Object[] getSections() { return mIndexer.getSections(); }
		 */
		public AsyncQueryHandler getQueryHandler() {
			return mQueryHandler;
		}

		public void setActivity(ChannelListActivity newactivity) {
			mActivity = newactivity;
		}

		@Override
		public void changeCursor(Cursor cursor) {
			if (cursor != mActivity.mChannelCursor) {
				mActivity.mChannelCursor = cursor;
				getColumnIndices(cursor);
				super.changeCursor(cursor);
			}
		}

		private void getColumnIndices(Cursor cursor) {

			if (cursor != null) {
				mTitleIdx = cursor
						.getColumnIndexOrThrow(SzRSSReader.Channels.TITLE);
			}
		}

		class ChannelAlphabetIndexer extends AlphabetIndexer {

			public ChannelAlphabetIndexer(Cursor cursor, int sortedColumnIndex,
					CharSequence alphabet) {
				super(cursor, sortedColumnIndex, alphabet);
			}

			@Override
			protected int compare(String word, String letter) {
				// String wordKey = MediaStore.Audio.keyFor(word);
				// String letterKey = MediaStore.Audio.keyFor(letter);
				String wordKey = word;
				String letterKey = letter;

				if (wordKey.startsWith(letter)) {
					return 0;
				} else {
					return wordKey.compareTo(letterKey);
				}
			}
		}

	}
}
